import 'dart:convert';
import 'dart:math';
import 'dart:typed_data';
import 'package:crypto/crypto.dart';

class HmacUtil {
  /// 生成 HMAC 签名
  static String generateSignature(
    String method,
    String path,
    String? queryString,
    String? bodyHash,
    int timestamp,
    String nonce,
    String clientSecret,
  ) {
    final signString = [
      method.toUpperCase(),
      path,
      queryString ?? '',
      bodyHash ?? '',
      timestamp.toString(),
      nonce
    ].join('\n');

    final key = utf8.encode(clientSecret);
    final bytes = utf8.encode(signString);

    final hmacSha256 = Hmac(sha256, key);
    final digest = hmacSha256.convert(bytes);

    return base64Encode(digest.bytes);
  }

  /// 计算请求体的 SHA-256 十六进制哈希
  static String hashBody(String? body) {
    if (body == null || body.isEmpty) return '';
    final bytes = utf8.encode(body);
    final digest = sha256.convert(bytes);
    return _bytesToHex(digest.bytes);
  }

  /// 计算请求体的 SHA-256 十六进制哈希（字节数组版本）
  static String hashBodyBytes(Uint8List? bodyBytes) {
    if (bodyBytes == null || bodyBytes.isEmpty) return '';
    final digest = sha256.convert(bodyBytes);
    return _bytesToHex(digest.bytes);
  }

  /// 验证签名（常量时间比较，防止时序攻击）
  static bool verifySignature(
    String receivedSignature,
    String method,
    String path,
    String? queryString,
    String? bodyHash,
    int timestamp,
    String nonce,
    String clientSecret,
  ) {
    final expectedSignature = generateSignature(
      method,
      path,
      queryString,
      bodyHash,
      timestamp,
      nonce,
      clientSecret,
    );

    return _constantTimeEquals(
      utf8.encode(expectedSignature),
      utf8.encode(receivedSignature),
    );
  }

  /// 生成随机的 nonce 值
  static String generateNonce([int length = 16]) {
    const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    final random = Random.secure();
    final buffer = StringBuffer();
    for (int i = 0; i < length; i++) {
      buffer.write(charset[random.nextInt(charset.length)]);
    }
    return buffer.toString();
  }

  /// 生成当前时间戳（毫秒）
  static int generateTimestamp() {
    return DateTime.now().millisecondsSinceEpoch;
  }

  /// 验证时间戳（防止重放攻击）
  static bool isTimestampValid(int clientTimestamp, int toleranceMillis) {
    final now = DateTime.now().millisecondsSinceEpoch;
    return (now - clientTimestamp).abs() <= toleranceMillis;
  }

  /// 常量时间比较
  static bool _constantTimeEquals(List<int> a, List<int> b) {
    if (a.length != b.length) return false;
    var diff = 0;
    for (var i = 0; i < a.length; i++) {
      diff |= a[i] ^ b[i];
    }
    return diff == 0;
  }

  /// 字节数组转十六进制字符串
  static String _bytesToHex(List<int> bytes) {
    final buffer = StringBuffer();
    for (final byte in bytes) {
      buffer.write(byte.toRadixString(16).padLeft(2, '0'));
    }
    return buffer.toString();
  }
}
